package org.visionlibrary.image.filters.effects;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.media.jai.TiledImage;

import org.visionlibrary.image.acquisition.ImageFactory;
import org.visionlibrary.image.model.AbstractFilter;


public class LocalHistogramDilation extends AbstractFilter {
	protected int size = 9;
	
	public LocalHistogramDilation(int size) {
		super();
		this.size = size;
	}

	@Override
	public TiledImage applyFilter(TiledImage src, TiledImage dest) {
		if (null == src)
			throw new NullPointerException("Source image is null.");

		if (null == dest)
			dest = (new ImageFactory()).createCompatibleImage(src);
		int maxX = src.getWidth();
		int maxY = src.getHeight();
		int channels = src.getNumBands();

		int ApetureMin = -(size / 2);
		int ApetureMax = (size / 2);

		for (int x = 0; x < maxX; x++)
			for (int y = 0; y < maxY; y++) {
				List<LocalChannelHistogram> histograms = new ArrayList<LocalChannelHistogram>();
				for (int x2 = ApetureMin; x2 < ApetureMax; ++x2) {
					int tempX = x + x2;
					if (tempX >= 0 && tempX < dest.getWidth()) {
						for (int y2 = ApetureMin; y2 < ApetureMax; ++y2) {
							int tempY = y + y2;
							if (tempY >= 0 && tempY < dest.getHeight()) {
								List<Integer> samples = new ArrayList<Integer>();
								for (int ch = 0; ch < channels; ch++) {
									int pixel = src.getSample(tempX, tempY, ch);
									samples.add(pixel);
								}
								LocalChannelHistogram localHistogram = new LocalChannelHistogram(samples);
								if(histograms.contains(localHistogram))
									histograms.get(histograms.indexOf(localHistogram)).increment();
								else
									histograms.add(localHistogram);
							}
						}
					}
				}
				
				Collections.sort(histograms);
				List<Integer> chan = histograms.get(histograms.size()-1).getSample();
				for(int ch=0; ch < chan.size(); ch++) {
					int normalizedPixelVal = normalization.normalize(chan.get(ch));
					dest.setSample(x, y, ch, normalizedPixelVal);
				}
			}

		return dest;
	}
	
	static class LocalChannelHistogram implements Comparable<LocalChannelHistogram>{
		List<Integer> sample = null;
		int counter = 1;
		
		public LocalChannelHistogram(List<Integer> sample) {
			super();
			this.sample = sample;
		}

		public void increment() {
			this.counter++;
		}
		
		public List<Integer> getSample() {
			return sample;
		}

		@Override
		public int hashCode() {
			return this.sample.hashCode();
		}

		@Override
		public boolean equals(Object obj) {
			if(this == obj)
				return true;
			
			if(!(obj instanceof LocalChannelHistogram))
				return false;
			
			LocalChannelHistogram that = (LocalChannelHistogram) obj;
			return this.sample.equals(that.sample);
		}
		
		@Override
		public int compareTo(LocalChannelHistogram o) {
			return counter - o.counter;
		}
	}
}
